# encoding: utf-8

from constants import *
from conexion_cliente import Buffer

class Respuesta(object):
    """ Clase donde se guardan los datos parseados de una respuesta obtenida por
        el nodo, ya sea desde otro nodo o desde el índice
    """
    def __init__(self):
        self.err_code = None #el código de error es parte de TODAS las rtas
        self.gfl_resp = Gfl_Resp() #la respuesta tras un pedido get_file_listing
        self.gm_resp = Gm_Resp() #la respuesta tras un pedido get_metadata
        self.gsrc_resp = Gsrc_Resp() #la respuesta tras un pedido get_sources
        self.gslc_resp = Gslc_Resp() #la respuesta tras un pedido get_slice
        self.esta_completa = False #la respuesta que llego es completa
        self.first_ans = True #Se hace false después del primer pedazo de rta

    def parsear_rta(self, rta_string, num_funcion):
        """ Parsea la rta recibida por el nodo (rta_string). num_funcion es una
            constante definida en el módulo constants que asocia a cada nombre
            de función un número. Se usa para saber el formato de la respuesta
            a parsear
        """
        self.err_code = parse_err_code(rta_string)
        if (self.err_code == code_ok): #si hubo un error no me gasto en seguir
            if (num_funcion == num_gfl):
                self.gfl_resp.parse_gfl_resp(rta_string, self.esta_completa\
                                                self.first_ans)
            elif (num_funcion == num_gm):
                self.gm_resp.parse_gm_resp(rta_string, self.esta_completa,\
                                            self.first_ans)
            elif (num_funcion == num_gsrc):
                self.gsrc_resp.parse_gsrc_resp(rta_string, self.esta_completa,\
                                                self.first_ans)
            elif (num_funcion == num_gslc):
                self.gslc_resp.parse_gslc_resp(rta_string, self.esta_completa,\
                                                self.first_ans)
            #NOTA: si no se da ninguno de estos casos, ¿devuelvo algun codigo de
            # error especial?

    def get_err_code(self):
        """ Devuelve el código de error de self """
        return self.err_code

    """ Las siguientes funciones sirven para obtener la respuesta ya parseada
        de los comandos "interesantes" en el sentido de que la respuesta contie-
        ne algo más además del código de error.
        NOTA: ¡DEBE LLAMARSE DESPUÉS DE PARSEAR RESPUESTA! Esto debe ser che-
        queado por el llamador y es él el responsable (sí,me estoy lavando las
        manos)
    """
    def get_gfl_resp(self):
        return self.gfl_resp
    def get_gm_resp(self):
        return self.gm_resp
    def get_gsrc_resp(self):
        return self.gsrc_resp
    def get_gslc_resp(self):
        return self.gslc_resp

def parse_err_code(rta_string):
    """ Obtiene el código de error de rta_string """
    err_code = int(rta_string.split[0])
    return err_code

class Gfl_Resp(object):
    """ Clase contenedora para almacenar los datos recibidos en una rta tras un
        pedido get_file_listing
    """
    def __init__(self):
        self.lista_pares = [] #lista con los pares hashmd5 filename
        self.completa = false #la respuesta llego completa?
        self.buffer = Buffer() #buffer para ir guardando "pedazos" de rta
        self.first_chunk = True #es el primer pedazo que llega?

    def parse_gfl_resp(self, rta_string, esta_completa): 
        #extrae los datos de rta_string
        if (first_chunk):
            self.first_chunk = False #Acaba de llegar el primer pedazo
            if (rta_string[-4:] == "\r\n\r\n"):        
                #la respuesta esta completa. No se sabe si bien, pero completa
                self.completa = True
        else:
            self.buffer.almacenar_mensaje(rta_string)
            rta_string = buffer.devolver_mensaje()
            if (rta_string[-4:] == "\r\n\r\n"):
                #ahora sí está completa
                self.completa = True
        if (self.completa):
            #parseamos sólo si ya ha llegado la respuesta completa
            lista_aux = rta_string.split()
            i = 2
            while  (i < len(lista_aux)-1):
                """descartamos el primero y el segundo porq corresponden al
                código de error que ya ha sido parseado
                """
                curr_md5 = lista_aux[i]
                curr_fname = lista_aux[i+1]
                i += 2
                self.lista_pares.append(new_pair)
                
            
     

        lista_aux = rta_string.split()

            
        i = 1 #lista_aux[0] contiene el codigo de error q ya fue extraido
        while (i < len(lista_aux)-1):
            new_pair = int(lista_aux[i]), lista_aux[i+1]
            self.lista_pares.append(new_pair)
            i = i+2 #incrementamos en 2, pues cada par son dos entradas en la
                    #lista

    def get_lista_pares(self):
        return self.lista_pares

class Gm_Resp(object):
    """ Clase contenedora para almacenar los datos recibidos en una rta tras un
        pedido get_metadata
    """
    def __init__(self):
        self.filename = None #nombre del archivo
        self.filesize = 0 #tamaño del archivo
        self.md5list = [] #lista con los md5 de cada una de las partes del arch

    def parse_gm_resp(self, rta_string):
        lista_aux = rta_string.split()
        self.filename = lista_aux[1] #en lista_aux[0] esta el err_code
        self.fileseize = int(lista_aux[2])
        for i in range(3, len(lista_aux)):
            #ahora extraemos la lista de los md5
            self.md5list.append(int(lista_aux[i]))

    def get_filename(self):
        return self.filename
    def get_filesize(self):
        return self.filesize
    def get_md5list(self):
        return self.md5list

class Gsrc_Resp(object):
    """ Clase contenedora para almacenar los datos recibidos en una rta tras un
        pedido get_sources
    """
    def __init__(self):
        self.dir_list = [] # lista con direcciones de nodos en formato 
                           # (ip_del_nodo,puerto)

    def parse_gsrc_resp(self, rta_string):
        lista_aux = rta_string.split()
        for i in range(1, len(lista_aux)):
            aux_string = lista_aux[i]
            delim = string.find(":") #delim contiene la posicion del :, que
                                     #separa la dir ip del puerto
            ip_string = string[:delim]
            port = int(string[delim+1:len(string)]
            # NOTA: la direccion ip, deberia convertirla a un tipo numerico?
            new_pair = ip_string, port
            self.dir_list.append(new_pair)

    def get_dir_list(self):
        return self.dir_list


class Gslc_Resp(object):
    """ Clase contenedora para almacenar los datos recibido en una rta tras un
        pedido get_slice
    """
    def __init__(self):
        self.frag_list = []
        # contiene una lista con pares (tamaño_fragmento, fragmento)

    def parse_gslc_resp(self, rta_string):
        aux_string = rta_string.split("\r\n") #obtenemos c/u de las lineas
        for i in range(1, len(aux_string)-2):
            #descartamos el primero por ser el código de error, y los dos
            #últimos por corresponder al 0\r\n del final que no aporta
            curr_line = aux_string[i]
            #curr_line es de la forma "5 pepa"
            frag_size = curr_line.split()[0] #el tamaño es lo primero de
                                                  #cada línea
            data = curr_line[len(frag_size)+1:]
            frag_size = int(frag_size)
            new_pair = frag_size, data
            self.frag_list.append(new_pair)

    def get_frag_list(self):
        return self.frag_list